package smallfrench.moteur.lexer;

import smallfrench.moteur.lexer.err.ErreurFinFichierInattendue;
import smallfrench.moteur.lexer.err.ErreurLexemeAttendu;
import smallfrench.moteur.lexer.err.ErreurLexemeInattendu;
import smallfrench.moteur.lexer.err.ErreurLexer;
import smallfrench.moteur.lexer.lexemes.Lexeme;
import smallfrench.moteur.lexer.lexemes.LexemeChaine;

/**
 * Automate pour les chaines de caractères
 * @author antoine1023
 *
 */
public class AutomateChaine extends Automate {

	@Override
	public Lexeme analyser(LecteurChaine lect, Position debut)
			throws ErreurLexer {

		char c = lect.suivant();

		if (c == '"') {
			StringBuffer valeur = new StringBuffer();

			while (!lect.isEof()) {

				c = lect.suivant();

				if (c == '"')
					return new LexemeChaine(valeur.toString(),
							debut, lect.getPosition());

				if (c == '\\') { // Caractère d’échappement

					if (lect.isEof())
						throw new ErreurFinFichierInattendue();

					switch (c = lect.suivant()) {

					case 'n': // Nouvelle ligne LF
						valeur.append('\n');
						break;

					case 'r': // retour chariot CR
						valeur.append('\r');
						break;

					case 't': // tabulation
						valeur.append('\t');
						break;

					case '\\':
						valeur.append('\\');
						break;

					case '"':
						valeur.append('"');
						break;

					case 'u': { // Unicode en hexadécimal sur deux octets
						int u = lireOctetHexadecimal(lect) << 8
								| lireOctetHexadecimal(lect);
						System.out.println("AutomateChaine.analyser() " + u);
						valeur.append((char) u);
						break;
					}

					default:
						throw new ErreurLexemeInattendu(
								String.valueOf(c), debut);
					}
				} else {
					valeur.append(c);
				}
			}

			throw new ErreurLexemeAttendu("guillemet double \"", debut);
		}

		lect.precedent();

		return null;
	}

	private static int lireOctetHexadecimal(LecteurChaine lect)
			throws ErreurLexer {

		if (!lect.isEof()) {

			char a = lect.suivant();
			int ia = hexCharEnEntier(a);
			if (ia == -1)
				throw new ErreurLexemeInattendu(
						String.valueOf(a), lect.getPosition());

			if (!lect.isEof()) {
				char b = lect.suivant();
				int ib = hexCharEnEntier(b);
				if (ib == -1)
					throw new ErreurLexemeInattendu(
							String.valueOf(b), lect.getPosition());

				return (ia << 4) | ib;
			}
		}

		throw new ErreurFinFichierInattendue();
	}

	private static final byte hexCharEnEntier(char c) {
		if (c >= '0' && c <= '9')
			return (byte) (c - '0');
		else if (c >= 'a' && c <= 'f')
			return (byte) (c - 'a' + 10);
		else if (c >= 'A' && c <= 'F')
			return (byte) (c - 'A' + 10);
		else return -1;
	}
}
